#ifndef _GONGFU_PANDA_DEFINES_H_
#define _GONGFU_PANDA_DEFINES_H_
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <event.h>
#include <iostream>
#include <sys/socket.h>
#include <sys/un.h>
#include <signal.h>
#include <sys/resource.h>
#include <sys/uio.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>

///////////////
#define    PANDA_ERROR_SYSTEM  -3  
#define    PANDA_ERROR_ARGS    -2
#define    PANDA_MC_DOWN       -1 
#define    PANDA_MC_OK          0
#define    PANDA_MC_FAIL        1
#define    PANDA_MC_RESTART     2
#define    PANDA_MC_NEXT        3
#define    PANDA_MC_LIVE        0 
#define    PANDA_MC_NULL        4

//////////////
#define TRANSMIT_COMPLETE   0
#define TRANSMIT_INCOMPLETE 1
#define TRANSMIT_SOFT_ERROR 2
#define TRANSMIT_HARD_ERROR 3

#define DATA_BUFFER_SIZE 2048
#define UDP_READ_BUFFER_SIZE 65536
#define UDP_MAX_PAYLOAD_SIZE 1400
#define UDP_HEADER_SIZE 8
#define MAX_SENDBUF_SIZE (256 * 1024 * 1024)
#define ITEMS_PER_ALLOC 64

/* I'm told the max legnth of a 64-bit num converted to string is 20 bytes.
 *  * Plus a few for spaces, \r\n, \0 */
/** Initial size of the sendmsg() scatter/gather array. */
#define IOV_LIST_INITIAL 400
/** Initial number of sendmsg() argument structures to allocate. */
#define MSG_LIST_INITIAL 10
/** High water marks for buffer shrinking */
#define READ_BUFFER_HIGHWAT 8192
#define IOV_LIST_HIGHWAT 600
#define MSG_LIST_HIGHWAT 100
#define MAX_VERBOSITY_LEVEL 2


#define PANDA_HASH_KEY           "_hash"
#define PANDA_CACHE_KEY          "_key"
#define PANDA_CACHE_VAL          "_val"
#define PANDA_CACHE_EXPIRE       "_expire"

typedef unsigned int rel_time_t;
/* An item in the connection queue. */
typedef struct conn_queue_item CQ_ITEM;
struct conn_queue_item {
    int     sfd;
    int     init_state;
    int     event_flags;
    int     read_buffer_size;
    int     is_udp;
    CQ_ITEM *next;
};

/* A connection queue. */
typedef struct conn_queue CQ;
struct conn_queue {
    CQ_ITEM *head;
    CQ_ITEM *tail;
    pthread_mutex_t lock;
    pthread_cond_t  cond;
};

typedef struct {
    pthread_t thread_id;        /* unique ID of this thread */
    struct event_base *base;    /* libevent handle this thread uses */
    struct event notify_event;  /* listen event for notify pipe */
    int notify_receive_fd;      /* receiving end of notify pipe */
    int notify_send_fd;         /* sending end of notify pipe */
    CQ  new_conn_queue;         /* queue of new connections to handle */
} LIBEVENT_THREAD;


struct settings {
    size_t maxbytes;
    int maxconns;
    int port;
    char *inter;
    int verbose;
    char *socketpath;   /* path to unix socket if using local socket */
    int access;  /* access mask (a la chmod) for unix domain socket */
    int num_threads;        /* number of libevent threads to run */
};

enum conn_states {
    conn_listening,  /** the socket which listens for connections */
    conn_read,       /** reading in a command line */
    conn_write,      /** writing out a simple response */
    conn_nread,      /** reading in a fixed number of bytes */
    conn_swallow,    /** swallowing unnecessary bytes w/o storing */
    conn_closing,    /** closing this connection */
    conn_mwrite,     /** writing out many items sequentially */
};

typedef struct conn conn;
struct conn {
    int    sfd;
    int    state;
    struct event event;
    short  ev_flags;
    short  which;   /** which events were just triggered */

    char   *rbuf;   /** buffer to read commands into */
    char   *rcurr;  /** but if we parsed some already, this is where we stopped */
    unsigned int    rsize;   /** total allocated size of rbuf */
    unsigned int    rbytes;  /** how much data, starting from rcur, do we have unparsed */

    char   *wbuf;
    char   *wcurr;
    unsigned int   wsize;
    unsigned int   wbytes;
    int    write_and_go; /** which state to go into after finishing current write */
    void   *write_and_free; /** free this memory after finishing writing */

 /* data for UDP clients */
//    struct sockaddr request_addr; /* Who sent the most recent request */
//    socklen_t request_addr_size;
//   unsigned char *hdrbuf; /* udp packet headers */
//   int    hdrsize;   /* number of headers' worth of space is allocated */
//    int    binary;    /* are we in binary mode */
    //   int    bucket;    /* bucket number for the next command, if running as
    //                      a managed instance. -1 (_not_ 0) means invalid. */
    //int    gen;       /* generation requested for the bucket */
    bool   noreply;   /* True if the reply should not be sent. */
    conn   *next;     /* Used for generating a list of conn structures */
};


#endif // _GONGFU_PANDA_DEFINES_H_
